package com.zhongen.wflow.workflow.config.listener;

import cn.hutool.core.util.StrUtil;
import com.zhongen.wflow.mapper.WflowUsersMapper;
import com.zhongen.wflow.workflow.bean.dto.NotifyDto;
import com.zhongen.wflow.workflow.execute.ListenerExecutor;
import com.zhongen.wflow.workflow.service.NotifyService;
import com.zhongen.wflow.workflow.service.WxCommonService;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.EndEvent;
import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.delegate.event.AbstractFlowableEngineEventListener;
import org.flowable.engine.delegate.event.FlowableActivityEvent;
import org.flowable.engine.delegate.event.FlowableMultiInstanceActivityCompletedEvent;
import org.flowable.engine.delegate.event.FlowableProcessTerminatedEvent;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author : willian fu
 * @date : 2022/8/27
 */
@Slf4j
@Component
public class GlobalTaskListener extends AbstractFlowableEngineEventListener {

	@Autowired
	private NotifyService notifyService;

	@Autowired
	private RuntimeService runtimeService;

	@Autowired
	private ListenerExecutor listenerExecutor;

	@Autowired
	private WflowUsersMapper wflowUsersMapper;

	@Autowired
	private WxCommonService wxCommonService;

	@Override
	protected void taskCreated(FlowableEngineEntityEvent event) {
		log.debug("监听到任务[{}]创建", event.getExecutionId());
		super.taskCreated(event);
	}

	@Override
	protected void processCreated(FlowableEngineEntityEvent event) {
		listenerExecutor.doProcessChangeHandler("start", event.getProcessInstanceId(), event.getProcessDefinitionId());
		// 流程创建成功
		super.processCreated(event);
	}

	@Override
	protected void activityStarted(FlowableActivityEvent event) {
		log.info("流程[{}]进入ID[{}]的[{}]节点", event.getProcessInstanceId(), event.getActivityId(), event.getActivityName());
		listenerExecutor.doProcessNodeChangeHandler("enter", event.getProcessInstanceId(),
				event.getProcessDefinitionId(), event.getActivityId(), event.getActivityType());
		super.activityStarted(event);
	}

	@Override
	protected void activityCompleted(FlowableActivityEvent event) {
		processLeaveNodeEventHandler(event);
		super.activityCompleted(event);
	}

	@Override
	protected void multiInstanceActivityCompletedWithCondition(FlowableMultiInstanceActivityCompletedEvent event) {
		processLeaveNodeEventHandler(event);
		super.multiInstanceActivityCompletedWithCondition(event);
	}

	@Override
	protected void taskCompleted(FlowableEngineEntityEvent event) {
		log.debug("监听到任务[{}]结束", event.getExecutionId());
		super.taskCompleted(event);
	}

	@Override
	protected void processCompleted(FlowableEngineEntityEvent event) {
		ProcessInstance instance = runtimeService.createProcessInstanceQuery()
			.processInstanceId(event.getProcessInstanceId())
			.singleResult();
		notifyService.notify(NotifyDto.builder()
			.target(instance.getStartUserId())
			.instanceId(event.getProcessInstanceId())
			.processDefId(event.getProcessDefinitionId())
			.title("您的审批已通过")
			.type(NotifyDto.TypeEnum.SUCCESS)
			.content(StrUtil.builder("您提交的审批【", instance.getProcessDefinitionName(), "】已经通过").toString())
			.build());

		Date date = new Date();
		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String time = formatter.format(date);
		String name = wflowUsersMapper.selectNameByUserId(instance.getStartUserId());
		wxCommonService.sendMsgs(instance.getId(),"同意",name,time,instance.getProcessDefinitionName());

		listenerExecutor.doProcessChangeHandler("pass", event.getProcessInstanceId(), event.getProcessDefinitionId());
		log.info("[{}]审批流程[{}}]通过", instance.getProcessInstanceId(), instance.getProcessDefinitionName());
		super.processCompleted(event);
	}

	@Override
	protected void processCompletedWithTerminateEnd(FlowableEngineEntityEvent event) {
		// 通过判断流程实例的endActivityId = refuse-end / cancel-end 判断是撤销还是驳回
		if (event instanceof FlowableProcessTerminatedEvent) {
			Object cause = ((FlowableProcessTerminatedEvent) event).getCause();
			if (cause instanceof EndEvent) {
				String endNode = ((EndEvent) cause).getId();
				if ("refuse-end".equals(endNode)) {
					log.debug("监听到流程[{}]被驳回", event.getProcessInstanceId());
					listenerExecutor.doProcessChangeHandler("refuse", event.getProcessInstanceId(),
							event.getProcessDefinitionId());
					ProcessInstance instance = runtimeService.createProcessInstanceQuery()
							.processInstanceId(event.getProcessInstanceId())
							.singleResult();
					Date date = new Date();
					SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
					String time = formatter.format(date);
					String name = wflowUsersMapper.selectNameByUserId(instance.getStartUserId());
					wxCommonService.sendMsgs(instance.getId(),"不同意",name,time,instance.getProcessDefinitionName());
				}
				else if ("cancel-end".equals(endNode)) {
					listenerExecutor.doProcessChangeHandler("cancel", event.getProcessInstanceId(),
							event.getProcessDefinitionId());
					log.debug("监听到流程[{}]被撤销", event.getProcessInstanceId());
					ProcessInstance instance = runtimeService.createProcessInstanceQuery()
							.processInstanceId(event.getProcessInstanceId())
							.singleResult();
					Date date = new Date();
					SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
					String time = formatter.format(date);
					String name = wflowUsersMapper.selectNameByUserId(instance.getStartUserId());
					wxCommonService.sendMsgs(instance.getId(),"撤销",name,time,instance.getProcessDefinitionName());
				}
			}
		}
		super.processCompletedWithTerminateEnd(event);
	}

	private void processLeaveNodeEventHandler(FlowableActivityEvent event) {
		log.info("流程[{}]离开ID[{}]的[{}]节点", event.getProcessInstanceId(), event.getActivityId(), event.getActivityName());
		listenerExecutor.doProcessNodeChangeHandler("leave", event.getProcessInstanceId(),
				event.getProcessDefinitionId(), event.getActivityId(), event.getActivityType());
	}

}
